package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.agent.CourseClient;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.common.ResourceTypeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;


/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    @Autowired
    private CourseClient courseClient;

    /* 保存媒资信息 增 开启事务
        /关键数据
            dto 不为空
            机构ID--companyId
            文件名称--filename
            文件标识--fileId
            文件类型--type

        业务数据：
        判断媒资信息是否已经存在(已保存过了)
        判断文件类型，是视频，则获取视频播放地址(每小时刷新一次)并保存

        进行保存数据

        返回数据
     */
    @Transactional
    public MediaDTO createMedia(MediaDTO dto) {
        // dto 不为空
        // 机构ID--companyId
        // 文件名称--filename
        // 文件标识--fileId
        //文件类型--type
        ExceptionCast.cast(ObjectUtils.isEmpty(dto), MediaErrorCode.E_140008);

        if (ObjectUtils.isEmpty(dto.getCompanyId()) ||
                StringUtil.isBlank(dto.getFileId()) ||
                StringUtil.isBlank(dto.getFilename()) ||
                StringUtil.isBlank(dto.getType())
        ) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }


        //判断媒资信息是否已经存在(已保存过了)--通过文件唯一标识 fileId
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getFileId, dto.getFileId());

        Media one = this.getOne(queryWrapper);
        //判断是否存在取反，存在应为true
        if (!ObjectUtils.isEmpty(one)) {
            ExceptionCast.cast(MediaErrorCode.E_140009);
        }
        //判断文件类型，是视频，则获取视频播放地址(每小时刷新一次)并保存
        if (ResourceTypeEnum.VIDEO.getCode().equals(dto.getType())) {
            try {
                DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);
                GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, dto.getFileId());
                //获取播放地址
                GetPlayInfoResponse.PlayInfo playInfo = response.getPlayInfoList().get(0);
                dto.setUrl(playInfo.getPlayURL());
            } catch (Exception e) {
                ExceptionCast.cast(MediaErrorCode.E_140012);
            }
        }

        //进行保存数据
        Media media = MediaConvert.INSTANCE.dto2entity(dto);
        //刚添加时，审核状态应为未审核
        media.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());
        boolean save = this.save(media);
        if (!save) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);

        return mediaDTO;
    }

    /*分页查询媒资信息
        关键数据
            params--当前页 每页条数
            mediaDTO --机构ID不为空
        业务数据
            存在 文件名 filename 根据名称模糊查询
            存在 文件类型 type 按文件类型查询
            判断媒资信息 是否查到
            判断媒资信息删除状态status 是否已被删除(逻辑删除)
            判断是否是同一机构
            审核状态 不能为 未审核状态

        返回数据
            在转成PageVO 格式返回
     */
    public PageVO<MediaDTO> queryMedia(PageRequestParams params, MediaDTO mediaDTO) {
        // 判断 当前页 每页条数 机构ID不为空
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();
        Long companyId = mediaDTO.getCompanyId();
        if (ObjectUtils.isEmpty(pageNo) ||
                ObjectUtils.isEmpty(pageSize) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
        // 判断 当前页 每页条数 不能为假数据 也就是不能小于1
        if (pageSize < 1 || pageNo < 1) {
            ExceptionCast.cast(MediaErrorCode.E_140010);
        }

        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getCompanyId, companyId);

        //存在 文件名 filename 根据名称模糊查询
        String filename = mediaDTO.getFilename();
        if (StringUtil.isNotBlank(filename)) {
            queryWrapper.like(Media::getFilename, filename);
        }
        //存在 文件类型 type 按文件类型查询
        String type = mediaDTO.getType();
        if (StringUtil.isNotBlank(type)) {
            queryWrapper.eq(Media::getType, type);
        }

        Page<Media> mediaPage = new Page<>(pageNo, pageSize);

        Page<Media> page = this.page(mediaPage, queryWrapper);


        List<Media> records = page.getRecords();
        //判断媒资信息 是否查到
        if (ObjectUtils.isEmpty(records)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }

        List<MediaDTO> dtoAList = new ArrayList<>();

        //判断媒资信息状态status--不能为删除
        //判断是否是同一机构

        List<Media> mediaList = page.getRecords();
        for (Media media : mediaList) {
            if (!(CommonEnum.DELETE_FLAG.getCode().equals(media.getStatus())) ||
                    companyId.equals(media.getCompanyId())) {
                //判断完成后 将数据添加到集合在返回
                MediaDTO dto = MediaConvert.INSTANCE.entity2dto(media);
                dtoAList.add(dto);
            }
        }

        PageVO<MediaDTO> mediaDTOS = new PageVO<>(dtoAList, page.getTotal(), pageNo, pageSize);

        return mediaDTOS;
    }

    /*媒资视频地址查询
      查询不开启事务
      关键数据 判断 mediaId，companyId 是否存在
      业务数据
      判断查到媒资信息是否存在
      判断文件格式 若是视频
      在根据文件标识去 阿里云查询获取 视频播放地址
      返回文件视频播放地址
     */
    public String getMediaURL(Long mediaId, Long companyId) {
        //判断 mediaId，companyId 是否存在
        if (ObjectUtils.isEmpty(mediaId) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
        //判断查到媒资信息是否存在
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getId, mediaId);
        queryWrapper.eq(Media::getCompanyId, companyId);
        Media media = this.getOne(queryWrapper);
        ExceptionCast.cast(ObjectUtils.isEmpty(media), MediaErrorCode.E_140005);

        //判断文件格式 不是视频不能预览视频
        String type = media.getType();
        if (!ResourceTypeEnum.VIDEO.getCode().equals(type)) {
            ExceptionCast.cast(MediaErrorCode.E_140013);
        }
        //若是视频 通过文件标识 去阿里云查询播放地址
        String url = null;
        try {
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);
            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, media.getFileId());
            //获取播放地址
            GetPlayInfoResponse.PlayInfo playInfo = response.getPlayInfoList().get(0);
            url = playInfo.getPlayURL();
        } catch (Exception e) {
            //e.printStackTrace();
            ExceptionCast.cast(MediaErrorCode.E_140012);
        }
        return url;
    }

    /*
      根据 媒资ID 机构ID删除媒资信息
      删除开启事务
      关键数据  判断 mediaId，companyId 是否存在
      业务数据
      判断媒资信息是否存在，同一机构，是否删除
      判断媒资是否关联课程信息，因为课程信息在另一个微服务，需要远程调用
      根据查询结果 判断 已关联课程信息，不可删除
      删除媒资信息 判断是否删除成功
     */
    @Transactional
    public void removeMedia(Long mediaId, Long companyId) {

        //判断 mediaId，companyId 是否存在
        if (ObjectUtils.isEmpty(mediaId) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }

        //判断查到媒资信息是否存在  是否删除
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getId, mediaId);
        queryWrapper.eq(Media::getCompanyId, companyId);
        Media media = this.getOne(queryWrapper);
        //是否存在
        ExceptionCast.cast(ObjectUtils.isEmpty(media), MediaErrorCode.E_140005);
        //是否删除
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCodeInt().equals(media.getStatus()), MediaErrorCode.E_140016);

        //判断媒资是否关联课程信息，因为课程信息在另一个微服务，需要远程调用
        RestResponse<Integer> response = courseClient.queryTeachPlanMedia(mediaId);
        Integer result = response.getResult();
        if (result > 0) {
            //大于0说明 该媒资已绑定过课程信息 不可删除
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        //为绑定课程信息 则可进行删除
        LambdaUpdateWrapper<Media> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Media::getId,mediaId);
       //逻辑删除 将状态 改为删除
        updateWrapper.set(Media::getStatus,CommonEnum.DELETE_FLAG.getCodeInt());
        boolean update = this.update(updateWrapper);

        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }

    }


    /*运营翻页查询全部媒资信息
    关键数据
    params--当前页 每页条数 不能为假数据
    判断传入参数 有 媒资名字或类型就添加到条件中，媒资名字用模糊查询
    业务数据
       判断媒资信息 是否存在
       判断 媒资信息 状态不能为删除


     */
    public PageVO<MediaDTO> queryMediaM(PageRequestParams params, MediaDTO mediaDTO) {
        Integer pageSize = params.getPageSize();
        Long pageNo = params.getPageNo();

        // 判断 当前页 每页条数 不能为假数据 也就是不能小于1
        if (pageSize < 1 || pageNo < 1) {
            ExceptionCast.cast(MediaErrorCode.E_140010);
        }

        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        //存在 文件名 filename 根据名称模糊查询
        String filename = mediaDTO.getFilename();
        if (StringUtil.isNotBlank(filename)) {
            queryWrapper.like(Media::getFilename, filename);
        }
        //存在 文件类型 type 按文件类型查询
        String type = mediaDTO.getType();
        if (StringUtil.isNotBlank(type)) {
            queryWrapper.eq(Media::getType, type);
        }

        Page<Media> mediaPage = new Page<>(pageNo, pageSize);

        Page<Media> page = this.page(mediaPage, queryWrapper);
        //判断媒资信息 是否存在
        List<Media> records = page.getRecords();
        if (ObjectUtils.isEmpty(records)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        List<MediaDTO> mediaDTOS = new ArrayList<>();
        //判断 媒资信息 状态不能为删除
        for (Media record : records) {
            if (!(CommonEnum.DELETE_FLAG.getCodeInt().equals(record.getStatus()))) {
                MediaDTO dto = MediaConvert.INSTANCE.entity2dto(record);
                mediaDTOS.add(dto);
            }
        }

        PageVO<MediaDTO> dtoPageVO = new PageVO<>(mediaDTOS, page.getTotal(), pageNo, pageSize);


        return dtoPageVO;
    }

    /*运营审核媒资信息
    修改开启事务
        关键数据判断 媒资ID 审核状态 不为空
        业务数据 根据媒资ID查询媒资信息，
        判断是否存在，是否删除
        修改数据
        判断有审核意见就添加
        修改审核状态
        判断是否修改成功
     */
    @Transactional
    public void createMediaM(MediaDTO mediaDTO) {
        // 媒资ID 审核状态 不为空
        Long dtoId = mediaDTO.getId();
        String auditStatus = mediaDTO.getAuditStatus();
        String auditMind = mediaDTO.getAuditMind();
        if (ObjectUtils.isEmpty(dtoId) ||
                StringUtil.isBlank(auditStatus)) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
        //根据媒资ID查询媒资信息
        Media mediaById = this.getById(dtoId);
        //判断是否存在，是否删除
        ExceptionCast.cast(ObjectUtils.isEmpty(mediaById), MediaErrorCode.E_140005);
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCodeInt().equals(mediaById.getStatus()), MediaErrorCode.E_140016);

        //修改数据
        LambdaUpdateWrapper<Media> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Media::getId, dtoId);

        //判断有审核意见就添加
        if (StringUtil.isNotBlank(auditMind)) {
            updateWrapper.set(Media::getAuditMind, auditMind);
        }
        //修改审核状态
        updateWrapper.set(Media::getAuditStatus, auditStatus);
        //判断是否修改成功
        boolean update = this.update(updateWrapper);

        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }


    }

    /*
    查询媒资
    关键数据  mediaId 不为空
    业务数据 查询到的媒资信息 是否存在 是否删除 审核状态是否为审核通过
    返回数据
     */
    public RestResponse<MediaDTO> getByIdMedia(Long mediaId) {
        //mediaId 不为空
        if (ObjectUtils.isEmpty(mediaId)){
           return RestResponse.validfail(MediaErrorCode.E_140008);
        }

        //查询到的媒资信息 是否存在 是否删除

        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)||
        CommonEnum.DELETE_FLAG.getCodeInt().equals(media.getStatus())){
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }
        //审核状态是否为审核通过
        if (!AuditEnum.AUDIT_PASTED_STATUS.getCode().equals(media.getAuditStatus())){
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }

        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
        RestResponse<MediaDTO> dtoRestResponse = RestResponse.success(mediaDTO);
        return dtoRestResponse;
    }
}
